package mapelements.foreground;

import java.io.Serializable;
import java.util.Vector;


/**rappresenta la classe che gestisce la messaggistica di un Foreground. Questa classe è molto utile
 * per trasmettere i messaggi di tipo ForegroundEvent agli eventuali altri Listener. In caso un oggetto voglia
 * trasmettere certe informazioni ad un observer (che non sono tuttavia presenti nell'albero generale dei Foreground)
 * <strong>deve</strong> estendere questa classe: per esempio se voglio che un certo oggetto ascolti la vita di un personaggio (che certo
 * non è un attributo nell'albero generale dei Foreground) deve estendere un pò di cose in modo da poter eseguire tale ascolto in
 * maniera più performante possibile; è infatti possibile creare un altro listener (LifeListener) ma così facendo si creerebbero più strutture di ascolto
 * che occuperebbero memoria. è quindi essenziale passare da questo Dispatcher. 
 * <p>Di cosa si necessita per creare nuovi listener estesi?
 * <ol>
 *  <li>bisogna creare un interfaccia listener che estenda ForegorundListener con i metodi sopra citati</li>
 *  <li>bisogna dire al Foreground quale classe di Dispatcher usare. Per farlo bisogna usare un'estensione di AbstractForegroundDispatcherFactory</li>
 *  <li>bisogna creare un nuovo event che estende ForegroundEvent</li>
 *  <li>bisogna estendere questa classe sovrascrivendo il metodo {@link #fireForegroundEvent(Foreground, int)}
 * </ol>
 * 
 * <p>come si fa ad estendere il metodo {@link #fireForegroundEvent(Foreground, int)}? Semplice!
 * Per ogni metodo che l'estensione del ForegroundEvent possiede basta inserire un valore costante di action e quindi
 * utilizzare un if che contempli quel detemrinato valore. In seguito basterà ciclare sui listeners (ricavabili da {@link #getListeners()})
 * e lanciare il metodo dell'interfaccia estendente ForegroudnListener!
 *<p>Per esempio, se abbiamo BeeListener con il metodo <code>Life0(BeeEvent arg0);</code> basterà estendere {@link #fireForegroundEvent(Foreground, int)} come di seguito:
 *<code>
 *<p>protected fireForegroundEvent(ForegroundEvent arg0,int action){
 *<p> super.fireForegroundEvent(arg0,action);
 *<p> if (action==BeeEvent.LIFE0){
 *<p>  for (ForegroundListener l:this.getListeners(){
 *<p>   try{
 *<p>    ((BeeListener)l).Life0((BeeEvent)arg0);
 *<p>   }catch (ClassCastException error){}
 *<p>  }
 *<p>  return;
 *<p> } 
 *<p>}
 *</code> 
 * 
 * @author koldar
 * @version 1.1
 */
public class ForegroundEventDispatcher implements Serializable{

	private static final long serialVersionUID = -4457691494027584362L;

	private Vector<ForegroundListener> listeners;
	
	public ForegroundEventDispatcher(){
		super();
		this.listeners=new Vector<ForegroundListener>(0,1);
	}
	
	public void addForegroundListener(ForegroundListener arg0){
		this.listeners.add(arg0);
	}
	
	public void removeForegroundListener(ForegroundListener arg0){
		this.listeners.remove(arg0);
	}
	
	/**quando evocato il metodo analizza il parametro <tt>action</tt> e, a seconda del suo valore, esegue
	 * un metodo diverso dei ForegroundListeners contenuti in {@link #listeners}. Il metodo va sovrascritto
	 * se si vuole usare un solo Listener per più cambiamenti di uno stesso Foreground.
	 * è consigliato inoltre richiamare super.fireForegroundEvent come prima riga del codice in quanto le sue casistiche
	 * solo le più comuni (quindi per motivi prestazionali). Inoltre, per ogni casitica, è opportuno inserire un <code>return;</code>
	 * alla fine (sempre per motivi prestazionali)
	 * 
	 * @param source il foreground che è stato modificato in suo qualche attributo
	 * @param action il tipo di modifica effettuata sul foreground
	 */
	public void fireForegroundEvent(Foreground source,int action){
		if (action==ForegroundEvent.SHAPECHANGED){
			for (ForegroundListener l:this.listeners){
				l.shapeChanged(new ForegroundEvent(source,action));
			}
			return;
		}
		if ((action==MapObjectEvent.POSITIONCHANGED)&&(source instanceof MapObject)){
			for (ForegroundListener l:this.listeners){
				l.positionChanged(new MapObjectEvent((MapObject)source,action));
			}
			return;
		}
		
	}
	
	/**clona il dispatcher; ciò che però non viene clonato sono i riferimenti ai listener contenuti. Per essere esatti
	 * la lista di listener viene semplicemente creata, ma viene lasciata vuota.
	 * <p>Estensioni di questa classe dovrebbero semplicemente impostare gli altri campi del Dispatcher, in quanto
	 * il {@link #listeners} viene già clonato.  
	 * 
	 */
	public ForegroundEventDispatcher clone() throws CloneNotSupportedException{
		ForegroundEventDispatcher result=(ForegroundEventDispatcher)super.clone();
		result.listeners=(Vector<ForegroundListener>) this.listeners.clone();
		return result;
	}

	/**
	 * @return the listeners. For further information visit {@link #listeners}
	 */
	protected Vector<ForegroundListener> getListeners() {
		return listeners;
	}
	
	
}
